// Author: Domien Nowicki

#include <QMessageBox>
#include <QFileDialog>
#include "colorcrazy.h"
#include "MapWidget.h"
#include "SingleGameWidget.h"
#include "HighscoreDialog.h"



ColorCrazy::ColorCrazy(QApplication *a, QWidget *parent, Qt::WFlags flags): QMainWindow(parent, flags), mapLoaded(false), gameLoaded(false), singleGame(0), versusGame(0)
{
	ui.setupUi(this);

	SetGameCleared();
}

ColorCrazy::~ColorCrazy()
{

}

// Setup ui state when a map is loaded
void ColorCrazy::SetMapLoaded()
{
	ui.actionSingleGame->setEnabled(mapLoaded);
	ui.actionVsComputer->setEnabled(mapLoaded);
	ui.actionSingleHighscores->setEnabled(mapLoaded);
	ui.actionVersusHighscores->setEnabled(mapLoaded);
}

// Setup ui state when a game is cleared
void ColorCrazy::SetGameCleared()
{
	ui.actionClear->setEnabled(false);
	ui.actionColorMap->setEnabled(false);
	ui.actionHint->setEnabled(false);
	SetMapLoaded();
}

// Setup ui state when a game is started
void ColorCrazy::SetGameStarted(Game* game)
{
	ui.actionClear->setEnabled(true);
	ui.actionSingleGame->setEnabled(false);
	ui.actionVsComputer->setEnabled(false);

	// The following actions depend on the game:
	ui.actionColorMap->setEnabled(game->isColorMapAllowed());
	ui.actionHint->setEnabled(game->isHintsAllowed());
}

void ColorCrazy::on_actionAbout_activated()
{
	QMessageBox::information(this, tr("Color Crazy"), tr("Color Crazy:\n\tA game based on the 4 color problem.\n\n\tAuthors: Bjorn Schobben, Domien Nowicki"));
}

void ColorCrazy::on_actionProperties_activated()
{
	PropertiesDialog *dialog = new PropertiesDialog(this, properties);
	dialog->show();

	QObject::connect(dialog, SIGNAL(accepted(const Properties&)), this, SLOT(OnPropertiesAccepted(const Properties&)));
}

void ColorCrazy::OnPropertiesAccepted(const Properties& newProperties)
{
	// Copy over properties
	this->properties = newProperties;
}


void ColorCrazy::OnGameStarted(Game* game)
{
	// Setup ui state
	SetGameStarted(game);
}

void ColorCrazy::OnGameStopped()
{
}

void ColorCrazy::on_actionQuit_activated()
{
	close();
}

void ColorCrazy::on_actionLoad_activated()
{
	// Ask which file to load
	QString qfilename = QFileDialog::getOpenFileName(this, tr("Open Map File"), "", tr("All map files (*.*)"));

	// valid filename?
	if (qfilename.length())
	{
		std::string filename = qfilename.toStdString();
		// Load file to local map
		mapLoaded = map.LoadFromFile(filename);

		QString message;

		if (mapLoaded)
		{
			message = tr("Map was loaded successfully.");
		}
		else
		{
			message = tr("An error occurred while loading map.");
		}

		if (mapLoaded)
		{
			// If map successfully loaded, try to load the highscore files
			highscoreSingle.LoadFromFile(SingleGameFilename(filename));
			highscoreVersus.LoadFromFile(VersusGameFilename(filename));
		}

		// Update ui
		SetMapLoaded();

		// Show message
		QMessageBox::information(this, tr("Loading map"), message);
	}
}

void ColorCrazy::on_actionSingleGame_activated()
{
	if (!mapLoaded)
	{
		QMessageBox::critical(this, tr("Single game"), tr("Please load a map first."));	
	}
	else if (!gameLoaded)
	{
		gameLoaded = true;

		// Start new single game
		singleGame = new SingleGameWidget(ui.frame, this->map, this->properties, this->highscoreSingle);
		ui.hboxLayout->addWidget(singleGame);

		// Connect signals
		QObject::connect(singleGame, SIGNAL(started(Game*)), this, SLOT(OnGameStarted(Game*)));
		QObject::connect(singleGame, SIGNAL(stopped()), this, SLOT(OnGameStopped()));

		// Start the game
		singleGame->Start();
	}
}

void ColorCrazy::on_actionVsComputer_activated()
{
	if (!mapLoaded)
	{
		QMessageBox::critical(this, tr("Versus game"), tr("Please load a map first."));	
	}
	else if (!gameLoaded)
	{
		gameLoaded = true;

		// Start new versus game
		versusGame = new VersusGameWidget(ui.frame, this->map, this->properties, this->highscoreVersus);
		ui.hboxLayout->addWidget(versusGame);

		// Connect signals
		QObject::connect(versusGame, SIGNAL(started(Game*)), this, SLOT(OnGameStarted(Game*)));
		QObject::connect(versusGame, SIGNAL(stopped()), this, SLOT(OnGameStopped()));

		// Start the game
		versusGame->Start();
	}
}

void ColorCrazy::on_actionColorMap_activated()
{
	// User wants to color the map automatically
	try
	{
		if (singleGame)
		{
			singleGame->ColorMap();
		}
		else if (versusGame)
		{
			versusGame->ColorMap();
		}
	} catch(...)
	{
		QMessageBox::critical(this, tr("Error"), tr("An internal error happened while trying to color the map"));	
		on_actionClear_activated();
	}
}

void ColorCrazy::on_actionHint_activated()
{
	// User wants a hint
	try
	{
		if (singleGame)
		{
			singleGame->Hint();
		}
		else if (versusGame)
		{
			versusGame->Hint();
		}
	} catch(...)
	{
		QMessageBox::critical(this, tr("Error"), tr("An internal error happened while trying to get a hint"));	
		on_actionClear_activated();
	}

}

void ColorCrazy::on_actionClear_activated()
{
	// Clear game widgets
	if (singleGame)
	{
		delete singleGame;

		singleGame = 0;
	}

	if (versusGame)
	{
		delete versusGame;

		versusGame = 0;
	}

	gameLoaded = false;

	// Update ui
	SetGameCleared();
}

// Get the highscore filename when given a mapfile
std::string ColorCrazy::SingleGameFilename(const std::string& mapFilename)
{
	return mapFilename.substr(0, mapFilename.find_last_of('.')).append(".shi");
}

std::string ColorCrazy::VersusGameFilename(const std::string& mapFilename)
{
	return mapFilename.substr(0, mapFilename.find_last_of('.')).append(".vhi");
}

// Show highscores
void ColorCrazy::on_actionSingleHighscores_activated()
{
	HighscoreDialog* dialog = new HighscoreDialog(this, highscoreSingle);

	dialog->show();
}

void ColorCrazy::on_actionVersusHighscores_activated()
{
	HighscoreDialog* dialog = new HighscoreDialog(this, highscoreVersus);

	dialog->show();
}
